//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

//#include "StdAfx.h"
#include "wintypes.h"
#include "FriendList.h"
#include "emule.h"

#include <wx/listimpl.cpp>
WX_DEFINE_LIST(FriendList);

CFriendList::CFriendList(void){
	LoadList();
	m_nLastSaved = ::GetTickCount();
}

CFriendList::~CFriendList(void)
{
	SaveList();
	for (FriendList::Node* pos = m_listFriends.GetFirst();pos != 0;pos=pos->GetNext())
	  delete pos->GetData();//m_listFriends.GetAt(pos);
	m_listFriends.Clear();//RemoveAll();
}

bool CFriendList::LoadList(){
	CFriend* Record = 0; 
	CFile file;
	//try {
		wxString strFileName =wxString(theApp.glob_prefs->GetAppDir()) +wxString("emfriends.met");
		if (!file.Open(strFileName,CFile::read))
			return false;
		uint8 header;
		file.Read(&header,1);
		if (header != MET_HEADER){
			file.Close();
			return false;
		}
		uint32 nRecordsNumber;
		file.Read(&nRecordsNumber,4);
		for (uint32 i = 0; i != nRecordsNumber; i++) {
			Record =  new CFriend();
			Record->LoadFromFile(&file);
			m_listFriends.Append(Record);//AddTail(Record);
		}
		file.Close();
		return true;
		//}
#if 0
	catch(CFileException* error){
		OUTPUT_DEBUG_TRACE();
		if (error->m_cause == CFileException::endOfFile)
			theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_EMFRIENDSINVALID));
		else{
			char buffer[150];
			error->GetErrorMessage(buffer,150);
			theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_READEMFRIENDS),buffer);
		}
		error->Delete();
		return false;
	}
#endif
}

void CFriendList::SaveList(){
	CFile file;
	wxString strFileName = wxString(theApp.glob_prefs->GetAppDir()) + wxString("emfriends.met");
	//if (!file.Open(strFileName.GetBuffer(),CFile::modeCreate|CFile::modeWrite))
	if(!file.Create(strFileName,TRUE)) {
	  // if this fail, emule will crash because this is called from OnClose
	  // and wxWindows will pop wxLog-window and at the same time application closes itself
	  // 
	  return;
	}
	uint8 header = MET_HEADER;
	file.Write(&header,1);
	uint32 nRecordsNumber = m_listFriends.GetCount();
	file.Write(&nRecordsNumber,4);
	for (FriendList::Node* pos = m_listFriends.GetFirst();pos != 0;pos=pos->GetNext()){
		pos->GetData()->WriteToFile(&file);
	}
	file.Close();
}

CFriend* CFriendList::LinkFriend(uchar* abyUserHash, uint32 m_dwIp, uint16 m_nPort){
	CFriend* backup_friend = NULL;
	for (FriendList::Node* pos = m_listFriends.GetFirst();pos != 0;pos=pos->GetNext()){
		CFriend* cur_friend = pos->GetData();
		if( cur_friend->m_dwLastUsedIP == m_dwIp && cur_friend->m_nLastUsedPort == m_nPort )
			backup_friend = cur_friend;
		if (!memcmp(cur_friend->m_abyUserhash, abyUserHash,16)){
		  //CTime lwtime;
		  cur_friend->m_dwLastSeen = time(NULL);//mktime(lwtime.GetLocalTm());
			if (cur_friend->m_LinkedClient){
				cur_friend->m_LinkedClient->m_Friend = NULL;
				cur_friend->m_LinkedClient = NULL;
			}
			return cur_friend;
		}
	}
	return backup_friend;
}

void CFriendList::RefreshFriend(CFriend* torefresh){
	if (m_wndOutput)
		m_wndOutput->RefreshFriend(torefresh);
}

void CFriendList::ShowFriends(){
	if (!m_wndOutput){
	

		return;
	}
	m_wndOutput->DeleteAllItems();
	for (FriendList::Node* pos = m_listFriends.GetFirst();pos != 0;pos=pos->GetNext()) {
	  CFriend* cur_friend = pos->GetData();//m_listFriends.GetAt(pos);
	  m_wndOutput->AddFriend(cur_friend);	
	}
}

//Added this to work with the IRC.. Probably a better way to do it.. But wanted this in the release..
void CFriendList::AddFriend( uchar t_m_abyUserhash[16], uint32 tm_dwLastSeen, uint32 tm_dwLastUsedIP, uint32 tm_nLastUsedPort, uint32 tm_dwLastChatted, wxString tm_strName, uint32 tm_dwHasHash){
	CFriend* Record = 0; 
	Record = new CFriend( t_m_abyUserhash, tm_dwLastSeen, tm_dwLastUsedIP, tm_nLastUsedPort, tm_dwLastChatted, tm_strName, tm_dwHasHash );
	m_listFriends.Append(Record);//AddTail(Record);
	ShowFriends();
}

// Added for the friends function in the IRC..
bool CFriendList::IsAlreadyFriend( uint32 tm_dwLastUsedIP, uint32 tm_nLastUsedPort ){
	for (FriendList::Node*pos = m_listFriends.GetFirst();pos != 0;pos=pos->GetNext()){
	  CFriend* cur_friend = pos->GetData();//m_listFriends.GetAt(pos);
		if ( cur_friend->m_dwLastUsedIP == tm_dwLastUsedIP && cur_friend->m_nLastUsedPort == tm_nLastUsedPort ){
			return true;
		}
	}
	return false;
}

void CFriendList::AddFriend(CUpDownClient* toadd){
	if (toadd->IsFriend())
		return;
	CFriend* NewFriend = new CFriend(toadd);
	toadd->m_Friend = NewFriend;
	m_listFriends.Append(NewFriend);//AddTail(NewFriend);
	if (m_wndOutput)
		m_wndOutput->AddFriend(NewFriend);	
}

void CFriendList::RemoveFriend(CFriend* todel){
	FriendList::Node* pos = m_listFriends.Find(todel);
	if (!pos){
		return;
	}
	if (todel->m_LinkedClient){
		todel->m_LinkedClient->SetFriendSlot(false);
		todel->m_LinkedClient->m_Friend = NULL;
		todel->m_LinkedClient = NULL;
	}
	if (m_wndOutput)
		m_wndOutput->RemoveFriend(todel);
	m_listFriends.DeleteNode(pos);//RemoveAt(pos);
	delete todel;
}

void CFriendList::RemoveAllFriendSlots(){
	for (FriendList::Node* pos = m_listFriends.GetFirst();pos != 0;pos=pos->GetNext()){
	  CFriend* cur_friend = pos->GetData();//m_listFriends.GetAt(pos);
		if (cur_friend->m_LinkedClient){
			cur_friend->m_LinkedClient->SetFriendSlot(false);
		}
	}
}

void CFriendList::Process()
{
// Madcat - No need to save friends every second, as they are saved during
//          exiting anyway.
//	if (::GetTickCount() - m_nLastSaved > 300000)
//		this->SaveList();
}
